/* 权限控制模块 */
// 导入 router 和 动态路由表
import router, { asyncRoutes } from './router'
import store from './store'
// 导入 进度条 模块和样式
import np from 'nprogress'
import 'nprogress/nprogress.css'

// 白名单 -> 不需要登录就可以访问的路由
const whiteList = ['/login', '/404']

// 全局前置守卫
router.beforeEach(async (to, from, next) => {
  // 在每个路由被访问到之前开启进度条
  np.start()
  // to： 到哪去，是要去的路由对象，里面包含很多属性，path，query，params，meta，fullpath
  // from: 从哪来
  // next: 函数，决定是否放行(路由能否被访问/跳转)
  // 根据用户是否登录决定是否放行？
  const hasToken = store.state.user.token
  if (hasToken) { // 登录了
    // 想去登录页
    if (to.path === '/login') {
      // 停留在原地（不跳转）
      next(false)
      np.done()
    } else {
      try {
        // try-catch只能获取同步代码的异常(错误)
        // 这里添加await关键字的目的是把异步代码变为同步代码，错误才能被捕获到
        // 用户登录成功 -> token -> 基于token获取当前用户信息 ->
        // -> 角色(等同于知道了权限) -> 开放相应的左侧菜单
        // -> 调用next() -> 放行(正常显示Layout)
        // 如果userId没有，说明没有获取过用户信息，这时才需要发请求
        if (!store.state.user.profile.userId) {
          // 触发action，获取用户资料
          const userObj = await store.dispatch('user/getProfileAction')
          // 获取用户拥有的左侧菜单权限（数组）
          const menus = userObj.roles.menus
          // 从动态路由表筛选出需要展示的路由
          // 触发action，实现筛选
          // vuex中，任何一个action的返回值都是Promise实例，要想拿到返回值，必须配合await
          const otherRoutes = await store.dispatch('permission/filterRoutesAction', menus)
          // addRoutes() 类似数组的push()，动态给路由表添加路由规则，接受一个数组
          router.addRoutes([
            // 展开筛选结果数组
            ...otherRoutes,
            { // 记住：让path为*的路由永远放在路由表的末尾，解决刷新会404的问题
              path: '*',
              redirect: '/404',
              hidden: true
            }
          ])
          // 重新进入一次，解决刷新会白屏的问题
          next({
            ...to, // 展开要去的路由对象的所有属性，包含要去的路径和参数
            replace: true// 直接替换当前的url地址，不出现的历史记录中
          })
          // 提前结束
          return
        }
      } catch (e) {
        console.dir(e)
      }
      next()// 正常放行
    }
  } else { // 未登录
    // 要去的路由在白名单数组中
    if (whiteList.includes(to.path)) {
      next() // 正常放行
    } else {
      // 跳转至登录，并且携带参数，方便登录成功做回跳（体验一级棒）
      next(`/login?redirect=${to.path}`)
      np.done()
    }
  }
})

// 全局后置守卫
router.afterEach(() => {
  // 在每个路由被访问到之后终止进度条
  np.done()
})
